use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet, BTreeMap};

/// Redis value types
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum RedisValue {
    String(String),
    List(Vec<String>),
    Set(HashSet<String>),
    Hash(HashMap<String, String>),
    ZSet(BTreeMap<String, f64>), // member -> score
}

impl RedisValue {
    /// Get the type name of the value
    pub fn type_name(&self) -> &'static str {
        match self {
            RedisValue::String(_) => "string",
            RedisValue::List(_) => "list",
            RedisValue::Set(_) => "set",
            RedisValue::Hash(_) => "hash",
            RedisValue::ZSet(_) => "zset",
        }
    }

    /// Convert to string if possible
    pub fn as_string(&self) -> Option<&String> {
        match self {
            RedisValue::String(s) => Some(s),
            _ => None,
        }
    }

    /// Convert to list if possible
    pub fn as_list(&self) -> Option<&Vec<String>> {
        match self {
            RedisValue::List(l) => Some(l),
            _ => None,
        }
    }

    /// Convert to mutable list if possible
    pub fn as_list_mut(&mut self) -> Option<&mut Vec<String>> {
        match self {
            RedisValue::List(l) => Some(l),
            _ => None,
        }
    }

    /// Convert to set if possible
    pub fn as_set(&self) -> Option<&HashSet<String>> {
        match self {
            RedisValue::Set(s) => Some(s),
            _ => None,
        }
    }

    /// Convert to mutable set if possible
    pub fn as_set_mut(&mut self) -> Option<&mut HashSet<String>> {
        match self {
            RedisValue::Set(s) => Some(s),
            _ => None,
        }
    }

    /// Convert to hash if possible
    pub fn as_hash(&self) -> Option<&HashMap<String, String>> {
        match self {
            RedisValue::Hash(h) => Some(h),
            _ => None,
        }
    }

    /// Convert to mutable hash if possible
    pub fn as_hash_mut(&mut self) -> Option<&mut HashMap<String, String>> {
        match self {
            RedisValue::Hash(h) => Some(h),
            _ => None,
        }
    }

    /// Convert to sorted set if possible
    pub fn as_zset(&self) -> Option<&BTreeMap<String, f64>> {
        match self {
            RedisValue::ZSet(z) => Some(z),
            _ => None,
        }
    }

    /// Convert to mutable sorted set if possible
    pub fn as_zset_mut(&mut self) -> Option<&mut BTreeMap<String, f64>> {
        match self {
            RedisValue::ZSet(z) => Some(z),
            _ => None,
        }
    }
}

impl From<String> for RedisValue {
    fn from(s: String) -> Self {
        RedisValue::String(s)
    }
}

impl From<&str> for RedisValue {
    fn from(s: &str) -> Self {
        RedisValue::String(s.to_string())
    }
}

impl From<Vec<String>> for RedisValue {
    fn from(l: Vec<String>) -> Self {
        RedisValue::List(l)
    }
}

impl From<HashSet<String>> for RedisValue {
    fn from(s: HashSet<String>) -> Self {
        RedisValue::Set(s)
    }
}

impl From<HashMap<String, String>> for RedisValue {
    fn from(h: HashMap<String, String>) -> Self {
        RedisValue::Hash(h)
    }
}

impl From<BTreeMap<String, f64>> for RedisValue {
    fn from(z: BTreeMap<String, f64>) -> Self {
        RedisValue::ZSet(z)
    }
}